package tests.model_tests;

import static org.junit.Assert.*;

import org.junit.Test;

import application.models.datalayer.Attribute;
import application.models.exceptions.DataTypeException;

public class Attribute_test {

	@Test
	public void dataTypeToClassTest(){

		// 4 data types are supported: DATE, INTEGER, TEXT and BOOLEAN
		// Test that these are supported
		try{

			Attribute.getClassForDataType("DATE");
			Attribute.getClassForDataType("INTEGER");
			Attribute.getClassForDataType("TEXT");
			Attribute.getClassForDataType("BOOLEAN");

		} catch(DataTypeException e){

			fail("Cannot conversion of the required data types.");
		}

		// Test that non-supported values fails
		boolean invalidDataTypeHandlingFailure = true;
		try{

			Attribute.getClassForDataType("");

		} catch(DataTypeException e){

			invalidDataTypeHandlingFailure = false;
		}
		if(invalidDataTypeHandlingFailure) fail("");

		// Test that null values are handled correctly as a special negative test
		boolean nullHandlingFailure = true;
		try{

			Attribute.getClassForDataType(null);

		} catch(NullPointerException e){

			nullHandlingFailure = false;
		} catch(DataTypeException e){/*IGNORE*/}
		if(nullHandlingFailure) fail("Improper handling of null values");	
	}

	@Test
	public void constructorTest() throws DataTypeException {

		String dataType = "INTEGER";
		String name = "id";
		String dataSetOwner = "cars";
		boolean isMandatory = true;
		Object value = new Integer(2);

		// Test a valid case
		new Attribute(dataType, name, dataSetOwner, isMandatory, value);

		boolean failure;

		// Test invalid null values
		failure = true;
		try{ new Attribute(null, name, dataSetOwner, isMandatory, value); }
		catch(NullPointerException e){failure = false;}
		if(failure) fail();

		failure = true;
		try{ new Attribute(dataType, null, dataSetOwner, isMandatory, value); }
		catch(NullPointerException e){failure = false;}
		if(failure) fail();

		failure = true;
		try{ new Attribute(dataType, name, null, isMandatory, value); }
		catch(NullPointerException e){failure = false;}
		if(failure) fail();

		// Test invalid empty values
		failure = true;
		try{ new Attribute("", name, dataSetOwner, isMandatory, value); }
		catch(IllegalArgumentException e){failure = false;}
		if(failure) fail();

		failure = true;
		try{ new Attribute(dataType, "", dataSetOwner, isMandatory, value); }
		catch(IllegalArgumentException e){failure = false;}
		if(failure) fail();

		failure = true;
		try{ new Attribute(dataType, name, "", isMandatory, value); }
		catch(IllegalArgumentException e){failure = false;}
		if(failure) fail();

		// Test that value may be null
		failure = false;
		try{ new Attribute(dataType, name, dataSetOwner, isMandatory, null); }
		catch(NullPointerException e){failure = true;}
		if(failure) fail();

		// Test that values not matching the passed data type fails
		failure = true;
		try{ new Attribute(dataType, name, dataSetOwner, isMandatory, new Object()); }
		catch(DataTypeException e){failure = false;}
		if(failure) fail();

		failure = true;
		try{ new Attribute("STRING", name, dataSetOwner, isMandatory, value); }
		catch(DataTypeException e){failure = false;}
		if(failure) fail();
	}

	// Test that getters return the correct values
	@Test
	public void getterTest() throws DataTypeException {

		String dataType = "INTEGER";
		String name = "id";
		String dataSetOwner = "cars";
		boolean isMandatory = true;
		Integer value = new Integer(2);

		Attribute test = new Attribute(dataType, name, dataSetOwner, isMandatory, value);

		if(!dataType.equals(test.getDataType())) fail();
		if(!name.equals(test.getName())) fail();
		if(!dataSetOwner.equals(test.getDataSetOwner())) fail();
		if(isMandatory != test.isMandatory()) fail();
		if(!value.equals(test.getValue())) fail();
	}

	// Test that setters work properly
	@Test
	public void setterTest() throws DataTypeException {

		String dataType = "INTEGER";
		String name = "id";
		String dataSetOwner = "cars";
		boolean isMandatory = true;
		Object value = new Integer(2);

		Attribute test = new Attribute(dataType, name, dataSetOwner, isMandatory, value);

		Object setValue;


		// Test set values null, illegal data type and legal data type
		setValue = null;
		try{
			test.setValue(setValue);
			assertNull(test.getValue());
		} catch(DataTypeException e){

			fail();
		}

		setValue = "We succede in failing :D (I hope)"; // Must fail!
		try{
			test.setValue(setValue);
			fail(); // We fail if we ever get this far
		} catch(DataTypeException e){
		}

		setValue = new Integer(4);
		try{
			test.setValue(setValue);
			assertEquals(4, test.getValue());
		} catch(DataTypeException e){

			fail();
		}	
	}

	// Test supportsValue method
	@Test
	public void supportsTest() throws DataTypeException {

		String dataType = "INTEGER";
		String name = "id";
		String dataSetOwner = "cars";
		boolean isMandatory = true;
		Object value = new Integer(2);

		Attribute test = new Attribute(dataType, name, dataSetOwner, isMandatory, value);

		assert(test.supportsValue(new Integer(3)) == true); // Must succeed
		assert(test.supportsValue("") == false); // Must fail by casting an exception
		assert(test.supportsValue(null) == false); // Must fail by casting an exception
	}

	// Test equals functionality
	@Test
	public void equalsTest() throws DataTypeException {

		// An array of attributes varying in 1-2 values
		Attribute[] variations = new Attribute[]{
				new Attribute("INTEGER", "id", "cars", true, new Integer(2)),
				new Attribute("TEXT", "id", "cars", true, "Must be changed too to prevent errors"),
				new Attribute("INTEGER", "cardescription_id", "cars", true, new Integer(2)),
				new Attribute("INTEGER", "id", "cardescription", true, new Integer(2)),
				new Attribute("INTEGER", "id", "cars", false, new Integer(2)),
				new Attribute("INTEGER", "id", "cars", false, new Integer(6))
		};

		// Test that each attribute in the variations array is not equal to any other than itself
		for(int i = 0; i<variations.length; ++i){

			for(int j = i+1; j<variations.length; ++j){

				if(variations[i].equals(variations[j])) fail();
			}
		}

		Attribute[] variationsCopy = new Attribute[]{
				new Attribute("INTEGER", "id", "cars", true, new Integer(2)),
				new Attribute("TEXT", "id", "cars", true, "Must be changed too to prevent errors"),
				new Attribute("INTEGER", "cardescription_id", "cars", true, new Integer(2)),
				new Attribute("INTEGER", "id", "cardescription", true, new Integer(2)),
				new Attribute("INTEGER", "id", "cars", false, new Integer(2)),
				new Attribute("INTEGER", "id", "cars", false, new Integer(6))
		};

		// Test that each attribute in the variations array is considered equal to its copy
		for(int i = 0; i<variations.length; ++i){

			if(!variations[i].equals(variationsCopy[i])) fail();
		}
	}

}
